import axios from 'axios'
import CryptoJS from 'crypto-js'
import ApiError from './error'
import store from '@/store'
import { ElMessage } from 'element-plus'
import route from '@/router/index'
axios.defaults.baseURL = process.env.VUE_APP_API_HOST
axios.defaults.headers.post['Content-Type'] = 'application/json'

axios.interceptors.request.use(function (config) {
  if (store.state.token) {
    config.headers.Authorization = store.state.token
  }

  let signStr = ''
  const timestamp = Date.parse(new Date().toString()) / 1000
  let contentType = null
  if (config.data) {
    switch (config.method) {
      case 'post':

        if (config.data instanceof FormData) {
          config.headers.post['Content-Type'] = 'multipart/form-data'
        }
        contentType = config.headers.post['Content-Type']
        break
      case 'put':
        if (config.data instanceof FormData) {
          config.headers.put['Content-Type'] = 'multipart/form-data'
        }
        contentType = config.headers.put['Content-Type']
        break
      case 'patch':
        if (config.data instanceof FormData) {
          config.headers.patch['Content-Type'] = 'multipart/form-data'
        }
        contentType = config.headers.patch['Content-Type']
        break
      case 'get':
        break
    }

    if (contentType && contentType.match(/application\/json/gm) != null) {
      // application/json
      // eslint-disable-next-line no-debugger
      signStr = JSON.stringify(config.data)
    } else {
      // form
      // eslint-disable-next-line no-debugger
      const datamap = GetDataMap(config.data)
      signStr = SignStrFromForm(datamap)
    }
  } else if (config.params) {
    const datamap = GetDataMap(config.params)
    signStr = SignStrFromForm(datamap)
  }

  config.headers.Sign = SignString(signStr, timestamp)
  config.headers.Timestamp = timestamp
  return config
})

axios.interceptors.response.use(async function (response) {
  if (response.data.Code !== 200) {
    ElMessage.error(response.data.Message)
    if (response.data.Code === 10001) {
      store.dispatch('logout')
      route.push('/login')
      console.log(route)
    } else {
      throw new ApiError(response.data.Message, response.data.Code)
    }
  }
  response.data = response.data.Data
  return response
}, function (error) {
  const message = '网络请求错误 ' + error.message
  ElMessage.error(message)
  return Promise.reject(new ApiError(message, -1))
})
// 获取数据表单字典
function GetDataMap (obj) {
  if (!obj) {
    return null
  }
  const datas = new Map()
  if (obj instanceof FormData) {
    for (const key of obj.keys()) {
      datas.set(key.toString(), obj.getAll(key))
    }
  } else {
    for (const i in obj) {
      const key = i.toString()
      datas.set(key, obj[i])
    }
  }
  return datas
}

function SignStrFromForm (dataMap) {
  const keys = []
  for (const key of dataMap.keys()) {
    keys.push(key)
  }
  keys.sort(function (a, b) { // 按大写字母表排序
    if (a.toUpperCase() < b.toUpperCase()) {
      return -1
    }
    return 1
  })
  const strList = []
  for (const key of keys) {
    const value = dataMap.get(key)
    let isFile = false
    let valueStrs = value.toString()
    if (value instanceof Array) { // 如果是数组
      for (const v of value) {
        if (v instanceof File) {
          isFile = true
          break
        }
      }
      if (!isFile) {
        valueStrs = value.map(function (item) {
          return item.toString()
        }).join(',')
      }
    } else if (value instanceof File) {
      isFile = true
      valueStrs = value.toString()
    }
    if (isFile) {
      // 跳过文件类型，不直接参与签名
      continue
    }
    // 按key=value拼接
    strList.push(`${key}=${valueStrs}`)
  }
  // 按key1=value1&key2=value2拼接
  return strList.join('&')
}

function SignString (str, timestamp) {
  str = `${str}${timestamp}`
  const sha = CryptoJS.SHA256(str.toUpperCase()).toString().toUpperCase()
  return CryptoJS.MD5(sha).toString().toUpperCase()
}

export default {
  install (app) {
    app.config.globalProperties.$net = axios
  }
}
